﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Grishko.SerilizeTools;
using System.Collections;

namespace Grishko.DataTier.SqlSentence
{
    public class Word: EntitySingle 
    {

        public static Word.OperatorTypes[] GetAllowedOperatorsForPropertyType(SrchItemInfo.PropertyControlType SentenceWordOperatorTypesVal)
        {
            return WordScriptor.AllowedOperators(SentenceWordOperatorTypesVal);

        }
        
        public static OperatorTypes  ConverStringToOperatorType(string sOperator)
        {
            
            if(OperatorTypes .LIKE.ToString ().ToUpper ()==sOperator .ToUpper ())
                        return OperatorTypes .LIKE ;

            if (OperatorTypes.LESS .ToString().ToUpper() == sOperator.ToUpper())
                return OperatorTypes.LESS ;
            
            if (OperatorTypes.MORE .ToString().ToUpper() == sOperator.ToUpper())
                return OperatorTypes.MORE ;

            if (OperatorTypes.NOT_EQUALLY .ToString().ToUpper() == sOperator.ToUpper())
                return OperatorTypes.NOT_EQUALLY;

            if (OperatorTypes.NOT_EQUALLY.ToString().ToUpper() == sOperator.ToUpper())
                return OperatorTypes.EQUALLY;

            if (OperatorTypes.BETWEEN.ToString().ToUpper() == sOperator.ToUpper())
                return OperatorTypes.BETWEEN;

            if (OperatorTypes.EQUALLY.ToString().ToUpper() == sOperator.ToUpper())
                return OperatorTypes.EQUALLY;


            return OperatorTypes.LIKE; 

        }
        
        public static string ConvertWordTypesToTxt(WordTypes obj)
        {
            if(obj ==WordTypes .AND )
                                return "И";
            return "ИЛИ";
        }

        public static string ConvertOperatorTypesToTxt(OperatorTypes obj)
        {
            switch (obj)
            { 
                case OperatorTypes .LIKE :
                    return "ВКЛЮЧАЕТ";

                case OperatorTypes.LESS :
                    return "МЕНЬШЕ";

                case OperatorTypes.MORE :
                    return "БОЛЬШЕ";

                case OperatorTypes.NOT_EQUALLY:
                    return "НЕ РАВНО";

                case OperatorTypes.EQUALLY :
                    return "РАВНО";

                case OperatorTypes.BETWEEN :
                    return "В ДИАПАЗОНЕ";
            }
            return string.Empty;
        }

        /// <summary>
        /// Машинка по построению скрипта  поля 
        /// </summary>
        protected class WordScriptor
        {
            /// <summary>
            /// Набор разрешенных операций для заданного типа
            /// </summary>
            /// <param name="SentenceWordOperatorTypesVal"></param>
            /// <returns></returns>
            public static Word.OperatorTypes[] AllowedOperators(SrchItemInfo.PropertyControlType SentenceWordOperatorTypesVal)
            {
                switch (SentenceWordOperatorTypesVal)
                {
                    case SrchItemInfo.PropertyControlType.OnlyValueSrch:
                        return new Word.OperatorTypes[] { Word.OperatorTypes.EQUALLY };

                    case SrchItemInfo.PropertyControlType.Text:
                        return new Word.OperatorTypes[] { Word.OperatorTypes.LIKE, Word.OperatorTypes.NOT_EQUALLY, Word.OperatorTypes.EQUALLY};

                    case SrchItemInfo.PropertyControlType.Number:
                        return new Word.OperatorTypes[] { Word.OperatorTypes.NOT_EQUALLY, Word.OperatorTypes.EQUALLY, Word.OperatorTypes.LESS, Word.OperatorTypes.MORE, Word.OperatorTypes.BETWEEN };

                    case SrchItemInfo.PropertyControlType.Bool:
                        return new Word.OperatorTypes[] { Word.OperatorTypes.EQUALLY };

                    case SrchItemInfo.PropertyControlType.Date:
                        return new Word.OperatorTypes[] { Word.OperatorTypes.BETWEEN };

                    case SrchItemInfo.PropertyControlType.Tree:
                        return new Word.OperatorTypes[] { Word.OperatorTypes.LIKE, Word.OperatorTypes.EQUALLY };

                    //case SrchItemInfo.PropertyControlType.TreeRB:
                    //    return new Word.OperatorTypes[] { Word.OperatorTypes.LIKE, Word.OperatorTypes.EQUALLY };

                }
                return new Word.OperatorTypes[] { };
            }

            static void PopulateTemplate(Hashtable Templ, Hashtable Params, string ParamType, string Value, string Field)
            {


                Templ.Add(Word.OperatorTypes.EQUALLY, " PropertyName = '" + Field + "' AND  1=dbo.CompareValueText_MoreLess (PropertyValue,'{0}',{1}) ");
                Params.Add(Word.OperatorTypes.EQUALLY, new string[] { Value, "-1" });


                Templ.Add(Word.OperatorTypes.NOT_EQUALLY , " PropertyName = '" + Field + "' AND NOT  1=dbo.CompareValueText_MoreLess (PropertyValue,'{0}',{1}) ");
                Params.Add(Word.OperatorTypes.NOT_EQUALLY, new string[] { Value, "-1" });


                Templ.Add(Word.OperatorTypes.MORE , " PropertyName = '" + Field + "' AND  1=dbo.CompareValueText_MoreLess (PropertyValue,'{0}',{1}) ");
                Params.Add(Word.OperatorTypes.MORE, new string[] { Value, "0" });

                                
                Templ.Add(Word.OperatorTypes.LESS, " PropertyName = '" + Field + "' AND  1=dbo.CompareValueText_MoreLess (PropertyValue,'{0}',{1}) ");
                Params.Add(Word.OperatorTypes.LESS, new string[] {  Value, "1" });

                Templ.Add(Word.OperatorTypes.BETWEEN, " PropertyName = '" + Field + "' AND  1=dbo.CompareValueText_Between (PropertyValue,'{0}','{1}') ");
                Params.Add(Word.OperatorTypes.BETWEEN, Value.Split(";".ToCharArray()[0]));

            }

            Func<string[], string, string> GetFormatList = delegate(string[] Vars, string FormatString)
            {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < Vars.Length; i++)
                {
                    if (i > 0)
                        sb.Append(" OR ");
                    string[] Params = { Vars[i] };
                    string s = string.Format(FormatString, Params);
                    sb.Append(s);
                }
                return sb.ToString();
            };

            
            /// <summary>
            /// Получить инструкцию вида PropertyName = 'Client.Email' AND  ( PropertyValue  LIKE '%5665%')
            /// </summary>
            /// <param name="FieldValue"></param>
            /// <param name="useFullPropertyName">использовать полное имя свойства</param>
            /// <returns></returns>
            public string GetSql(Word fieldValue, bool useFullPropertyName, string tablePref)
            {
                string propertyName = (useFullPropertyName ? fieldValue.PropertyName : fieldValue.ShortPropertyName);

                if (fieldValue.PropertyType == SrchItemInfo.PropertyControlType.OnlyValueSrch)
                    return tablePref+".TxtPropertyValue LIKE '%" + fieldValue.Value.ToString() + "%'";

                if (fieldValue.PropertyType == SrchItemInfo.PropertyControlType.Text)
                    return GetSQL_TEXT(fieldValue.Value, propertyName, fieldValue.Operator,tablePref );

                if (fieldValue.PropertyType == SrchItemInfo.PropertyControlType.Number)
                    return GetSQL_NUMBER(fieldValue.Value, propertyName, fieldValue.Operator);


                if (fieldValue.PropertyType == SrchItemInfo.PropertyControlType.Date)
                    return GetSQL_Date(fieldValue.Value.ToString(), propertyName, fieldValue.Operator);


                if (fieldValue.Value is WordFieldValue_Bool)
                    return GetSQl_Bool((fieldValue.Value as WordFieldValue_Bool).bValue, propertyName, fieldValue.Operator,tablePref );


                if (fieldValue.PropertyType == SrchItemInfo.PropertyControlType.Tree)
                    return GetSQL_Tree(fieldValue.Value, propertyName, fieldValue.Operator);


                return string.Empty;

            }

            private string GetSQL_Tree(WordFieldValue Value, string Field, Word .OperatorTypes  Operation)
            {

                switch (Operation)
                {
                    case Word.OperatorTypes.EQUALLY:
                    case Word.OperatorTypes.LIKE:
                        return " PropertyName = '" + Field + "' AND  PropertyValue = 'OK'";
                }

                return string.Empty;

            }
            /// <summary>
            /// Формирует sql выражение для поля TXT операциям (=,!=,>,<)
            /// </summary>
            private string GetSQL_TEXT(WordFieldValue Value, string Field, Word .OperatorTypes  Operation, string tablePref)
            {
                switch (Operation)
                {
                    case Word.OperatorTypes.EQUALLY:
                        return tablePref+".PropertyName = '" + Field + "' AND  "+tablePref+".PropertyValue = '" + Value.ToString() + "'";

                    case Word.OperatorTypes.NOT_EQUALLY:
                        return tablePref+".PropertyName = '" + Field + "' AND  NOT ("+tablePref+"PropertyValue = '" + Value.ToString() + "') ";

                    case Word.OperatorTypes.LIKE:
                        {
                            string[] Vars = Value.ToString().Split(",".ToCharArray());
                            string s = GetFormatList(Vars, tablePref+".PropertyValue  LIKE '%{0}%'");
                            return tablePref+".PropertyName = '" + Field + "' AND  (" + s + ")";
                        }
                }

                return string.Empty;
            }

            /// <summary>
            /// Формирует sql выражение для поля TXT операциям (=,!=,>,<)
            /// </summary>
            private string GetSQL_NUMBER(WordFieldValue Value, string Field, Word .OperatorTypes   Operation)
            {
                Hashtable Templ = new Hashtable();
                Hashtable Params = new Hashtable();

                PopulateTemplate(Templ, Params, "decimal(15,2)", Value.ToString(), Field);


                //Шабон- параметры- результат
                string sTemplate = Templ[Operation].ToString(); ;
                string[] arrParams = (string[])Params[Operation];
                return string.Format(sTemplate, arrParams);

            }

            ///// <summary>
            ///// Формирует sql выражение для поля TXT операциям (=,!=,>,<)
            ///// </summary>
            private string GetSQL_Date(string Value, string Field, Word.OperatorTypes Operation)
            {
                Hashtable Templ = new Hashtable();
                Hashtable Params = new Hashtable();

                PopulateTemplate(Templ, Params, "datetime", Value, Field);


                //Шабон- параметры- результат
                string sTemplate = Templ[Operation].ToString(); ;
                sTemplate = sTemplate.Replace("CompareValueText_Between", "CompareValueText_Between_DT");
                string[] arrParams = (string[])Params[Operation];
                return string.Format(sTemplate, arrParams);

            }

            ///// <summary>
            ///// Формирует sql выражение для поля Bool операциям (=,!=,>,<)
            ///// </summary>
            private string GetSQl_Bool(bool Value, string Field, Word.OperatorTypes Operation, string tablePref)
            {
                switch (Operation)
                {
                    case Word.OperatorTypes.EQUALLY:
                        return tablePref + ".PropertyName = '" + Field + "' AND  " + tablePref + ".PropertyValue = '" + Value.ToString() + "'";
                }

                return string.Empty;
            }
        }

        public enum WordTypes{ AND, OR };
        
        public enum OperatorTypes { MORE, LESS, NOT_EQUALLY, EQUALLY, LIKE, BETWEEN }

        /// <summary>
        /// Полное имя свойства (п) Constraction.Side.OTS
        /// </summary>
        public string PropertyName { get; set; }

        /// <summary>
        /// Короткое имя свойства (п) OTS
        /// </summary>
        public string ShortPropertyName 
        {
            get 
            {
                string s = PropertyName;
                int i= s.LastIndexOf (".");
                return s.Substring((i==-1?0:i+1));
            }
        }

        /// <summary>
        /// путь  к свойство по дереву TagName
        /// </summary>
        public string TagPatch { get; set; }

        /// <summary>
        /// Тип слова - AND OR
        /// </summary>
        public WordTypes WordType { get; set; }

        /// <summary>
        /// Порядковый номер
        /// </summary>
        public int OrderNumber { get; set; }

        /// <summary>
        /// Операция
        /// </summary>
        public OperatorTypes Operator { get; set; }

        public string TxtKey { get; set; }

        public SrchItemInfo.PropertyControlType PropertyType { get; set; }

        /// <summary>
        /// Атрибутное описание поля
        /// </summary>
        public SrchItemInfo SrchItemInfo { get; set; }

        /// <summary>
        /// ParentTagName TagName - класса которому принадлежит свойство
        /// </summary>
        public TagNameInfo ParentTagName { get; set; }

        


        public WordFieldValue Value { get; set; }

        /// <summary>
        /// Уроавень параметра в дереве
        /// </summary>
        public int Level
        {
            get 
            {
                if (string.IsNullOrEmpty(PropertyName))
                    return 0;

                return PropertyName.Split(".".ToCharArray()[0]).Length; 
            }
        }

        public bool ImTmp { get; set; }

       [EntityNonSerialized ] 
        public bool ImFuncton 
       {
           get { return SrchItemInfo.ValueIsSqlFunction; }
       }

        /// <summary>
        /// получить sql соответсвующий слову
        /// </summary>
        /// <returns></returns>
        public string GetSql(bool useFullPropertyName,string tablePref)
        {
            WordScriptor w = new WordScriptor () ;
            return w.GetSql(this, useFullPropertyName, tablePref);
        }          
    }

    public class Sentence : EntitySingle
    {
        public class TWordList : EntityList
        {
            /// <summary>
            /// dthyenm слова определенного типа
            /// </summary>
            /// <param name="WordType"></param>
            /// <returns></returns>
            public List<Word> GetWords (Word.WordTypes WordType )
            {
                List<Word> l = this.ToList <Word>();
                
                var Items =
                from n in  l
               where
                   n.WordType  == WordType 
               select n;

                return Items.ToList<Word>();

            }

            /// <summary>
            /// dthyenm слова определенного типа исключая ExcludeFieldsType
            /// </summary>
            /// <param name="Type"></param>
            /// <param name="ExcludeFieldsType"></param>
            /// <returns></returns>
            public List<Word> GetWords(Word.WordTypes Type, SrchItemInfo.PropertyControlType ExcludeFieldsType)
            {
                List<Word> res =GetWords(Type);
                
                List<Word> result = new List<Word>();
                foreach (Word i in res)
                {
                    if (!i.PropertyType.Equals(ExcludeFieldsType))
                        result.Add(i);
                }

                return result;
            }

            public List<Word> GetWords(SrchItemInfo.PropertyControlType FieldsType)
            {
                List<Word> res = this.ToList<Word>();
                List<Word> result = new List<Word>();
                foreach (Word i in res)
                {
                    if (i.PropertyType.Equals(FieldsType))
                        result.Add(i);
                }

                return result;

            }

            /// <summary>
            /// Вернуть отсортированный список по OrderNumber
            /// </summary>
            /// <returns></returns>
            public List<Word> GetSortedWords()
            {
                List<Word> l = this.ToList<Word>();

                var Items =
                from n in l
                orderby n.OrderNumber 
                select n;

                return Items.ToList<Word>();

            }

            /// <summary>
            /// Имеет набор свойство типа OnlyValueSrchItem
            /// </summary>
            public bool IHaveOnlyValueSrchItem
            { 
            get{
                    for (int i = 0; i < this.Count; i++)
                        if ((this[i] as Word).PropertyType == SrchItemInfo.PropertyControlType.OnlyValueSrch)
                            return true;

                    return false;
            }
            }

            public override void Add(EntitySingle obj)
            {
                (obj as Word).OrderNumber = this.Count + 1;
                base.Add(obj);
            }


        
        }

        TWordList _WordList = new TWordList();
        public TWordList WordList { get { return _WordList; } }        

    }


}
